home *** CD-ROM | disk | FTP | other *** search
/ Precision Software Appli…tions Silver Collection 1 / Precision Software Applications Silver Collection Volume One (PSM) (1993).iso / demos / devel3.exe / DEMO3.C < prev    next >
C/C++ Source or Header  |  1992-06-05  |  42KB  |  1,690 lines

  1. /* A simple user-interface demo -- Version 3 */
  2.  
  3. /* Written by Bernie Roehl, February 1992 */
  4.  
  5. /* Latest version (re)written June 1992 */
  6.  
  7. /* Contact: broehl@sunee.waterloo.edu */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <math.h>
  12. #include <ctype.h>   /* toupper() */
  13. #include <string.h>  /* strrchr() */
  14. #include <mem.h>     /* memmove() */
  15. #include <time.h>    /* time(), ctime() */
  16. #include <dos.h>
  17.  
  18. #include "rend386.h"
  19. #include "userint.h"
  20. #include "plg.h"
  21. #include "segio.h"
  22. #include "segasupp.h"
  23.  
  24.             /* default screen data setup */
  25.  
  26. STEREO default_stereo = { 700, 240, 320, 55, 700, 10*65536L };
  27.  
  28. static VIEW default_view = {
  29.             0,0,-1000,         /* ex,ey,ez */
  30.             0,0,0,             /* pan,tilt,roll */
  31.             9*65536L,          /* zoom */
  32.             1000,15000,-5000,  /* lx,ly,lz */
  33.             0,319,0,200,       /* left,right,top,bottom */
  34.             1,100000,          /* hither, yon */
  35.             1/1.25*65536L,     /* aspect ratio */
  36.             0,                 /* flags */
  37.             0,0                /* no offset */
  38.             };                 /* don't init. matrix */
  39.  
  40.  
  41. static VIEW root;
  42. static VIEW *current_view;
  43. static VIEW left_view, right_view;
  44.  
  45. static int v_page = 0;     /* screen page swap variable */
  46.  
  47. static OBJLIST *objlist;   /* the linked list of objects in the scene */
  48.  
  49.  
  50. static l_x = 1000, l_y = 15000, l_z = -5000; /* light source */
  51.  
  52. static long center_d = 10000;
  53. static long center_x = 0;
  54. static long center_y = 0;
  55. static long center_z = 0;
  56. static long latitude = 0;
  57. static long longitude = 0;
  58. static long center_roll = 0;
  59.  
  60. static long light_d = 1000000;
  61.  
  62.  
  63. int running = 1;  /* non-zero until we're ready to exit */
  64. int redraw  = 1;  /* non-zero if we need a redraw */
  65. int review  = 1;  /* non-zero if we need to recompute current view */
  66.  
  67. int stereo_off = 0;
  68. int swap_eyes = 0;
  69. int mirror = 0;
  70.  
  71. extern int default_depth_sort;
  72.  
  73. int have_joystick = 0;     /* non-zero if we have one or more joysticks */
  74. joystick_data joy;
  75. int have_mouse = 0;    /* non-zero if we have a mouse */
  76.  
  77. static long spacestep = 10L;  /* "granularity" of motion */
  78. static char *in_filename = "";
  79.  
  80. #define to_rad(a) ((a) * 3.14159262 / 180.0)
  81. #define sine(x)   sin(to_rad(x/65536L))
  82. #define cosine(x) cos(to_rad(x/65536L))
  83.  
  84. static int lastkey = 0;
  85. static int nextolastkey = 0;
  86.  
  87. extern int rs232_port_adr;
  88.  
  89. char *progname = "demo     ";
  90.  
  91. extern unsigned paint;
  92.  
  93. static char glove_filename[] = "hand.fig";
  94. static SEGMENT *glove_seg;
  95. static SEGMENT *glove_joints[20];
  96. static glove_data glove_old, glove_new;
  97. static int glove_waits = 0;
  98. static use_glove = 0;
  99.  
  100. int fancy_background = 0;  /* if set, we display a fancy background */
  101. int reflection_pool = 0;   /* if set, draw a "reflecting pool" at the bottom of the screen */
  102. int have_logo = 0;         /* if set, we have a logo */
  103. int show_logo = 0;         /* if set, show the logo (if we have one) */
  104.  
  105. void main(int argc, char *argv[])
  106. {
  107.     OBJECT *obj, *lastobj;
  108.     void wrap();      /* wrap-up function, shuts everything down */
  109.     void joystick_calibration(), refresh_display();
  110.     unsigned getkey();
  111.     long x, y, z;
  112.     FILE *in;
  113.     int i;
  114.  
  115.     if ((progname = strrchr(argv[0], '.')) != NULL) *progname = '\0';
  116.     progname = argv[0];
  117.  
  118.     root = default_view;
  119.     current_view = &root;
  120.     compute_view_factors(current_view);
  121.     center_d = (default_stereo.world_scaling/65536.0) *
  122.         default_stereo.phys_convergence;
  123.  
  124.     setup_render();
  125.     atexit(wrap);
  126.  
  127.     objlist = new_objlist();
  128.     for (i = 1; i < argc; ++i)
  129.         {
  130.         if (argv[i][0] == '/' || argv[i][0] == '-')
  131.             {
  132.             switch(toupper(argv[i][1]))
  133.                 {
  134.                 case 'M': /* mirror stereo */
  135.                     mirror = 1;
  136.                     default_stereo.phys_screen_dist = 200;
  137.                     default_stereo.phys_convergence = 700;
  138.                     default_stereo.phys_screen_width = 120;
  139.                     default_stereo.pixel_width = 160;
  140.                     current_view->right = 159;
  141.                     compute_view_factors(current_view);
  142.                     center_d = (default_stereo.world_scaling/65536.0) *
  143.                         default_stereo.phys_convergence;
  144.                     break;
  145.                 case 'R':  /* swap eyes on Sega driver */
  146.                     swap_eyes = 1;
  147.                     break;
  148.                 case 'C':  /* set conv. distance */
  149.                     default_stereo.phys_screen_dist = atol(argv[++i]);
  150.                     compute_view_factors(current_view);
  151.                     center_d = (default_stereo.world_scaling/65536.0) *
  152.                         default_stereo.phys_convergence;
  153.                     break;
  154.                 case 'S':  /* set world scale */
  155.                     default_stereo.world_scaling = 65536.0*atof(argv[++i]);
  156.                     compute_view_factors(current_view);
  157.                     center_d = (default_stereo.world_scaling/65536.0) *
  158.                         default_stereo.phys_convergence;
  159.                     break;
  160.                 case 'E':  /* set eye spacing */
  161.                     default_stereo.phys_eye_spacing = atol(argv[++i]);
  162.                     break;
  163.                 case 'O':  /* turn off */
  164.                     stereo_off = 1;
  165.                     mirror = 1;
  166.                     break;
  167.                 case 'P':  /* depth sort by polys */
  168.                     default_depth_sort = DEEPEST;
  169.                     break;
  170.                 case 'A':  /* depth sort by polys--middle */
  171.                     default_depth_sort = AVERAGE;
  172.                     break;
  173.                 case '1': /* com 1 */
  174.                     rs232_port_adr = 0x3fc;
  175.                     break;
  176.                 case '2': /* com 2 */
  177.                     rs232_port_adr = 0x2fc;
  178.                     break;
  179.                 case 'G': /* enable glove */
  180.                     use_glove = 1;
  181.                     break;
  182.                 }
  183.             }
  184.         else
  185.             {
  186.             if ((in = fopen(in_filename = argv[i], "r")) == NULL)
  187.                 fprintf(stderr, "Could not open '%s'\n", argv[i]);
  188.             else
  189.                 if (strstr(in_filename,".plg"))    /* check if plg or fig file */
  190.                     {
  191.                     set_loadplg_offset(0,0,0);
  192.                     set_loadplg_scale(1,1,1);
  193.                     while ((obj = load_plg(in)) != NULL)
  194.                         {
  195.                         SEGMENT *s;
  196.                         add_to_objlist(objlist, lastobj = obj);
  197.                         if ((s = new_seg(NULL)) == NULL)
  198.                             fprintf(stderr, "Warning: out of memory while loading an object\n");
  199.                         else
  200.                             {
  201.                             seg_setrep(s, obj);
  202.                             update_segment(s);
  203.                             }
  204.                         set_object_owner(obj, s);
  205.                         if (spacestep < object_bounds(obj, &x, &y, &z)/5L)
  206.                             spacestep = object_bounds(obj, &x, &y, &z)/5L;
  207.                         }
  208.                 if (load_err)
  209.                     {
  210.                     fprintf(stderr, "Load error: %d\n", load_err);
  211.                     getkey();
  212.                     }
  213.                 }
  214.             else   /* default: figure load at start */
  215.                 {
  216.                 SEGMENT *s, *readseg();
  217.                 int c;
  218.                 set_readseg_objlist(objlist);
  219.                 if ((s = readseg(in, NULL)) == NULL)
  220.                     fprintf(stderr, "Could not open '%s'\n", argv[i]);
  221.                 else
  222.                     update_segment(s);
  223.                 }
  224.             fclose(in);
  225.             }
  226.         }
  227.     if (use_glove)
  228.         {
  229.         if ((in = fopen(glove_filename, "r")) == NULL)
  230.             fprintf(stderr, "Could not open '%s'\n", glove_filename);
  231.         else
  232.             {
  233.             SEGMENT *readseg();
  234.             set_readseg_objlist(objlist);
  235.             set_readseg_seglist(glove_joints,20);
  236.             if ((glove_seg = readseg(in, NULL)) == NULL)
  237.                 fprintf(stderr, "Bad glove figure file!");
  238.             else
  239.                 update_segment(glove_seg);
  240.             fclose(in);
  241.             }
  242.         }
  243.  
  244.     if (enter_graphics())
  245.         {
  246.         fprintf(stderr, "Could not enter graphics mode\n");
  247.         exit(1);
  248.         }
  249.  
  250.     if (use_glove)
  251.         {
  252.         glove_init(1);
  253.         if (mirror == 0)
  254.             {
  255.             init_SG_interrupt(switch_sega,glove_int_handler,6500);  /* start Sega interrupt */
  256.             atexit(sega_off);
  257.             }
  258.         else
  259.             init_SG_interrupt(NULL, glove_int_handler,6500);
  260.         }
  261.     else
  262.         {
  263.         if (mirror == 0)
  264.             {
  265.             init_SG_interrupt(switch_sega,NULL,0);  /* start Sega interrupt */
  266.             atexit(sega_off);
  267.             }
  268.         }
  269.  
  270.     have_logo = load_logo("logo.pcx");
  271.  
  272.     if ((have_mouse = mouse_init()) != 0) mouse_show(v_page);
  273.  
  274. #ifdef USE_JOYSTICK
  275.     if ((have_joystick = joystick_check()) != 0)
  276.         {
  277.         popmsg("Joystick found -- use it?");
  278.         if (toupper(getkey()) == 'Y')
  279.             {
  280.             refresh_display();
  281.             joystick_calibration(&joy);
  282.             }
  283.         else
  284.             have_joystick = 0;
  285.         refresh_display();
  286.         }
  287. #endif
  288.  
  289.     if (use_glove)
  290.         {
  291.         popmsg("Waiting for glove...");
  292.         while (!glove_ready())
  293.             if (kbhit())
  294.                 {
  295.                 getch();
  296.                 running = 0;
  297.                 exit(0);
  298.                 }
  299.         refresh_display();
  300.         glove_read(&glove_old);
  301.         }
  302.  
  303.     while (running)
  304.         {
  305.         int x, y;
  306.         unsigned buttons;
  307.         char c;
  308.         void glove_update();
  309.  
  310.         if (have_mouse)
  311.             if (mouse_read(&x, &y, &buttons))
  312.                 do_mouse(x, y, buttons);
  313.         if (have_joystick)
  314.             if (joystick_read(&joy))
  315.                 do_joy(&joy);
  316.         if (bioskey(1)) {
  317.             do_key(nextolastkey=getkey());
  318.             lastkey = nextolastkey;
  319.             }
  320.         if (use_glove && glove_ready() == 0) glove_waits++;
  321.         if (use_glove) glove_update();
  322.  
  323.         if (redraw)
  324.             {
  325.             refresh_display();
  326.             if (use_glove)
  327.                 {
  328.                 char w[20];
  329.                 sprintf(w,"%d",glove_waits);
  330.                 setup_hdwe(0);
  331.                 printxyc(20,190,0,w);
  332.                 reset_hdwe();
  333.                 glove_waits = 0;
  334.                 }
  335.             }
  336.         }
  337.     }
  338.  
  339.  
  340. static char *closing_msg[] = {
  341.     "",
  342.     "The libraries used in this package are available on the Internet,",
  343.     "via anonymous ftp to sunee.uwaterloo.ca in pub/rend386.",
  344.     "",
  345.     "For more information, send e-mail to:",
  346.     "    Bernie Roehl  (broehl@sunee.uwaterloo.ca)",
  347.     "    Dave Stampe   (dstampe@sunee.uwaterloo.ca)",
  348.     "",
  349.     NULL};
  350.  
  351.  
  352. void wrap()        /* end program */
  353. {
  354.     int i;
  355.  
  356.     if (have_joystick) joystick_quit();
  357.     if (have_mouse) mouse_deinit();
  358.     exit_graphics();
  359.     reset_render();
  360.     for (i = 0; closing_msg[i]; ++i)
  361.         fprintf(stderr, "%s\n", closing_msg[i]);
  362.     exit(0);
  363. }
  364.  
  365.  
  366. /***************/
  367.  
  368. static long fbend[4] =  { 0L, 30*65536L, 60*65536L, 75*65536L };
  369.  
  370. static long tbbend[4] = { -30*65536L, -37*65536L, -50*65536L, -65*65536L };
  371.  
  372. static long ttbend[4] = { 0L, 25*65536L, 50*65536L, 75*65536L };
  373.  
  374. void glove_update()
  375. {
  376.     int fp, fm, fi, ft;
  377.  
  378.     if (glove_ready == 0) return;
  379.     glove_read(&glove_new);
  380.     if (glove_new.x != glove_old.x ||
  381.         glove_new.y != glove_old.y ||
  382.         glove_new.z != glove_old.z ||
  383.         glove_new.rot != glove_old.rot ||
  384.         glove_new.fingers != glove_old.fingers )
  385.         {
  386.         glove_old = glove_new;
  387.         abs_move_segment(glove_seg,
  388.             glove_new.x*15, glove_new.y*15, glove_new.z*-100);
  389.         abs_rot_segment(glove_seg,
  390.             80*65536L, 20*65536L, (glove_new.rot-1)*-30*65536L);
  391.         ft = (glove_new.fingers >> 6) & 3;
  392.         fi = (glove_new.fingers >> 4) & 3;
  393.         fm = (glove_new.fingers >> 2) & 3;
  394.         fp = (glove_new.fingers >> 0) & 3;
  395.  
  396.         abs_rot_segment(glove_joints[1], 0L,tbbend[ft],0L);
  397.         abs_rot_segment(glove_joints[2], ttbend[ft],-90*65536L,37*65536L);
  398.         abs_rot_segment(glove_joints[3], fbend[fi],0L,0L);
  399.         abs_rot_segment(glove_joints[4], fbend[fi],0L,0L);
  400.         abs_rot_segment(glove_joints[5], fbend[fm],0L,0L);
  401.         abs_rot_segment(glove_joints[6], fbend[fm],0L,0L);
  402.         abs_rot_segment(glove_joints[7], fbend[fp],0L,0L);
  403.         abs_rot_segment(glove_joints[8], fbend[fp],0L,0L);
  404.         abs_rot_segment(glove_joints[9], fbend[fp],0L,0L);
  405.         abs_rot_segment(glove_joints[10], fbend[fp],0L,0L);
  406.  
  407. g:
  408.         update_segment(glove_seg);
  409.         redraw = 1;
  410.         }
  411. }
  412.  
  413.  
  414.  
  415. /***************/
  416.  
  417.  
  418. void polar_compute()
  419. {
  420.     MATRIX m,n;
  421.  
  422.     long x = 0;
  423.     long y = 0;
  424.     long z = -center_d;
  425.  
  426.     make_matrix(m,longitude,latitude,center_roll,0,0,0);
  427.     inverse_matrix(m,n);
  428.  
  429.     matrix_point(n,&x,&y,&z);
  430.     current_view->ex = x + center_x;
  431.     current_view->ey = y + center_y;
  432.     current_view->ez = z + center_z;
  433.  
  434.     x = l_x;  y = l_y;  z = l_z;
  435.     matrix_point(n,&x,&y,&z);
  436.     current_view->lx = x;
  437.     current_view->ly = y;
  438.     current_view->lz = z;
  439.     current_view->pan = latitude;
  440.     current_view->tilt = longitude;
  441.     current_view->roll = center_roll;
  442. }
  443.  
  444.  
  445.  
  446. extern int screen_clear_color;
  447.  
  448. static int ccyc[30]={ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
  449.                                             14,13,12,11,10,9,8,7,6,5,4,3,2,1 };
  450.  
  451. void background(int page, int top, int bot, int color)
  452. {
  453.     int inc = (top+(color&15))%30;
  454.     color &= 0xF0;
  455.  
  456.     for(;top<=bot;top+=2)
  457.         {
  458.         clr_block(0,top,319,top+1,page,color+ccyc[inc]);
  459.         if ((++inc) == 30) inc=0;
  460.         }
  461. }
  462.  
  463. void reflection(int page, int top, int bot, int step)
  464. {
  465.     int src = top-step;
  466.  
  467.     for( ; top <= bot; top++)
  468.         {
  469.         copy_block(page, 0, src, page, 0, top, 320, 1);
  470.         src -= step;
  471.         }
  472. }
  473.  
  474. void refresh_display()      /* now does stereo drawing */
  475. {
  476.     if (review)
  477.         {
  478.         polar_compute();
  479.         initialize_screen_factors(current_view);
  480.         fast_view_factors(current_view);
  481.         review = 0;
  482.         }
  483.  
  484.     if (stereo_off)
  485.         {
  486.         if (have_mouse) mouse_hide();
  487.         if (++v_page > 2) v_page = 0;  /* use 3 pages to avoid flicker */
  488.         if (fancy_background) {
  489.             if (have_logo && show_logo)
  490.                 background(v_page, 30, reflection_pool ? 160 : 199, 0xBF);
  491.             else
  492.                 background(v_page, 0, reflection_pool ? 160 : 199, 0xB0);
  493.             }
  494.         else
  495.             clear_display(v_page);
  496.         if (have_logo && show_logo)
  497.             copy_block(3, 0, 0, v_page, 0, 0, 320, 30);
  498.         set_drawpage(v_page);
  499.         render(objlist, current_view);
  500.         if (reflection_pool) reflection(v_page, 160, 199, 3);
  501.         set_vidpage(v_page, 0);
  502.         if (have_mouse) mouse_show(v_page);
  503.         redraw = 0;
  504.         return;
  505.         }
  506.  
  507.     if (have_mouse) mouse_hide();
  508.     v_page = v_page ^ 2;
  509.  
  510.     if (mirror)
  511.         {
  512.         clear_display(v_page);   /* left page */
  513.         set_drawpage(v_page);
  514.         mirr_stereo_view(current_view,&left_view,&default_stereo,LEFT_EYE);
  515.         render(objlist, &left_view);
  516.         mirr_stereo_view(current_view,&right_view,&default_stereo,RIGHT_EYE);
  517.         render(objlist, &right_view);
  518.         set_vidpage(v_page,0);
  519.         if (have_mouse) mouse_show(v_page);
  520.         }
  521.     else
  522.         {
  523.         clear_display(v_page);   /* left page */
  524.         set_drawpage(v_page);
  525.         make_stereo_view(current_view,&left_view,&default_stereo,LEFT_EYE);
  526.         render(objlist, &left_view);
  527.         setup_hdwe(0);
  528.         printxyc(20,10,0,"L");
  529.         reset_hdwe();
  530.         clear_display(v_page+1);   /* right page */
  531.         set_drawpage(v_page+1);
  532.         make_stereo_view(current_view,&right_view,&default_stereo,RIGHT_EYE);
  533.         render(objlist, &right_view);
  534.         setup_hdwe(0);
  535.         printxyc(300,10,0,"R");
  536.         reset_hdwe();
  537.         if (swap_eyes)
  538.             {
  539.             left_page = v_page+1;            /* display them now */
  540.             right_page = v_page;
  541.             }
  542.         else
  543.             {
  544.             left_page = v_page;
  545.             right_page = v_page+1;
  546.             }
  547.     if (have_mouse) mouse_show(v_page);
  548.     }
  549.  
  550.     redraw = 0;
  551. }
  552.  
  553.  
  554.  
  555. #define F1  0x3B00
  556. #define F2  0x3C00
  557. #define F3  0x3D00
  558. #define F4  0x3E00
  559. #define F5  0x3F00
  560. #define F6  0x4000
  561. #define F7  0x4100
  562. #define F8  0x4200
  563. #define F9  0x4300
  564. #define F10 0x4400
  565.  
  566. #define HOME      0x4700
  567. #define END       0x4F00
  568. #define PGUP      0x4900
  569. #define PGDN      0x5100
  570. #define LEFT      0x4B00
  571. #define RIGHT     0x4D00
  572. #define UP        0x4800
  573. #define DOWN      0x5000
  574. #define SHLEFT    0x4B01
  575. #define SHRIGHT   0x4D01
  576. #define SHUP      0x4801
  577. #define SHDOWN    0x5001
  578. #define SHPGUP    0x4901
  579. #define SHPGDN    0x5101
  580. #define CTRLLEFT  0x7300
  581. #define CTRLRIGHT 0x7400
  582. #define CTRLHOME  0x7700
  583. #define CTRLEND   0x7500
  584. #define CTRLPGUP  0x8400
  585. #define CTRLPGDN  0x7600
  586. #define ESC       0x001B
  587.  
  588. static int shifted = 0;
  589.  
  590. unsigned getkey()
  591. {
  592.     unsigned c;
  593.     union REGS regs;
  594.  
  595.     regs.h.ah = 2;
  596.     int86(0x16, ®s, ®s);
  597.     shifted = (regs.h.al & 3);
  598.     if ((c = bioskey(0)) & 0xFF) c &= 0xFF;
  599.     else if (shifted) c |= 1;
  600.     return c;
  601. }
  602.  
  603.  
  604. char *helptext[] = {
  605.         "              HELP",
  606.         "ARROWS       rotate around center",
  607.         "CTRL+ARROWS  twist head",
  608.         "Pgup/Pgdn    move in/out",
  609.         "Shift arrows move center X,Y",
  610.         "Shift Pgup/Pgdn    move center Z",
  611.         "CTRL PgUp/CTRL PgDn change zoom",
  612.         "R repeats last move 100x",
  613.         "I gives information  O sets options",
  614.         "0-9 set step size (0 = 10)",
  615.         "* resets to default view",
  616.         "Q quits, ? shows help",
  617.         "F1-F10 selects a view, V resizes view",
  618.         "C changes hither/yon clipping",
  619.         "D displays status information",
  620.         "L loads files,  S saves files",
  621.         "F loads figure files",
  622.         "P displays color palette",
  623.         "Z does object manipulation",
  624.         NULL
  625.         };
  626.  
  627. static int stepsize = 5;
  628.  
  629. #define ANGLESTEP (2L*65536L)
  630.  
  631. do_key(unsigned int c)
  632. {
  633.     void joystick_calibration(), disp_palette();
  634.     char buff[100];
  635.     FILE *in, *out;
  636.     long x, y, z;
  637.     int i, j;
  638.     MATRIX m,n;
  639.  
  640.     switch (c)
  641.         {
  642.         case LEFT:
  643.             latitude -= stepsize * ANGLESTEP;
  644.             review = redraw = 1;
  645.             break;
  646.         case RIGHT:
  647.             latitude += stepsize * ANGLESTEP;
  648.             review = redraw = 1;
  649.             break;
  650.         case UP:
  651.             longitude += stepsize * ANGLESTEP;
  652.             review = redraw = 1;
  653.             break;
  654.         case DOWN:
  655.             longitude -= stepsize * ANGLESTEP;
  656.             review = redraw = 1;
  657.             break;
  658.         case SHLEFT:
  659.             x = stepsize*spacestep/10;
  660.             y = 0;
  661.             review = redraw = 1;
  662.             goto fixcenter;
  663.         case SHRIGHT:
  664.             x = -stepsize*spacestep/10 ;
  665.             y = 0;
  666.             review = redraw = 1;
  667.             goto fixcenter;
  668.         case SHUP:
  669.             y = -stepsize*spacestep/10;
  670.             x = 0;
  671.             review = redraw = 1;
  672.             goto fixcenter;
  673.         case SHDOWN:
  674.             y = stepsize*spacestep/10;
  675.             x = 0;
  676.             review = redraw = 1;
  677. fixcenter:
  678.             z = 0;
  679.             make_matrix(m,longitude,latitude,center_roll,0,0,0);
  680.             inverse_matrix(m, n);
  681.             matrix_point(n,&x,&y,&z);
  682.             center_x += x;
  683.             center_y += y;
  684.             center_d -= z;
  685.             break;
  686.         case SHPGUP:
  687.             center_z += stepsize*spacestep/10;
  688.             review = redraw = 1;
  689.             break;
  690.         case SHPGDN:
  691.             center_z -= stepsize*spacestep/10;
  692.             review = redraw = 1;
  693.             break;
  694.         case CTRLLEFT:
  695.             center_roll -= stepsize * ANGLESTEP;
  696.             review = redraw = 1;
  697.             break;
  698.         case CTRLRIGHT:
  699.             center_roll += stepsize * ANGLESTEP;
  700.             review = redraw = 1;
  701.             break;
  702.         case PGUP:
  703.             center_d += (stepsize * spacestep);
  704.             review = redraw = 1;
  705.             break;
  706.         case PGDN:
  707.             center_d -= (stepsize * spacestep);
  708.             review = redraw = 1;
  709.             break;
  710.         case CTRLPGUP:
  711.             if (stereo_off)
  712.                 current_view->zoom *= 1.1;
  713.             else
  714.                 {
  715.                 default_stereo.world_scaling *= 1.1;
  716.                 center_d = (default_stereo.world_scaling/65536.0) *
  717.                     default_stereo.phys_convergence;
  718.                 }
  719.             review = redraw = 1;
  720.             break;
  721.         case CTRLPGDN:
  722.             if (stereo_off)
  723.                 current_view->zoom /= 1.1;
  724.             else
  725.                 {
  726.                 default_stereo.world_scaling /= 1.1;
  727.                 if (default_stereo.world_scaling <= 10)
  728.                     default_stereo.world_scaling = 11;
  729.                 center_d = (default_stereo.world_scaling/65536.0) *
  730.                     default_stereo.phys_convergence;
  731.                 }
  732.             review = redraw = 1;
  733.             break;
  734.         case 'U': case 'u':
  735.             current_view->pan += 180*65536L;
  736.             nextolastkey = 0;
  737.             review = redraw = 1;
  738.             break;
  739.         case '*':
  740.             current_view = &default_view;
  741.             center_d = (default_stereo.world_scaling/65536.0) *
  742.                 default_stereo.phys_convergence;
  743.             center_x = 0;
  744.             center_y = 0;
  745.             center_z = 0;
  746.             latitude = 0;
  747.             longitude = 0;
  748.             center_roll = 0;
  749.             nextolastkey = 0;
  750.             review = redraw = 1;
  751.             break;
  752.         case '0': stepsize = 10; break;
  753.         case '1': case '2': case '3': case '4':
  754.         case '5': case '6': case '7': case '8': case '9':
  755.             nextolastkey = 0;
  756.             stepsize = c - '0';
  757.             break;
  758.         case 'Q': case 'q': case ESC:
  759.             nextolastkey = 0;
  760.             popmsg("Really quit?");
  761.             if (toupper(getkey()) == 'Y') running = 0; else redraw = 1;
  762.             break;
  763.         case 'R': case 'r':
  764.             nextolastkey = lastkey;
  765.             if (lastkey)
  766.             for (i = 0; i < 100; i++) {
  767.                 do_key(lastkey);
  768.                 refresh_display();
  769.                 }
  770.             break;
  771.         case 'C': case 'c':
  772.             nextolastkey = 0;
  773.             popmsg("Change Hither or Yon?");
  774.             switch (toupper(getkey()))
  775.                 {
  776.                 case 'H':
  777.                     askfor("Enter hither value:", buff, 10);
  778.                     if (buff[0])
  779.                         current_view->hither = atof(buff);
  780.                     if (current_view->hither < 1) current_view->hither = 1;
  781.                     review = 1;
  782.                     break;
  783.                 case 'Y':
  784.                     askfor("Enter yon value:", buff, 10);
  785.                     if (buff[0]) current_view->yon = atof(buff);
  786.                     review = 1;
  787.                     break;
  788.                 default: break;
  789.                 }
  790.             redraw = 1;
  791.             break;
  792.         case 'D': case 'd':
  793.             nextolastkey = 0;
  794.             disp_status(current_view); redraw = 1; break;
  795.         case 'L': case 'l':
  796.             nextolastkey = 0;
  797.             askfor("File to load? ", buff, 15);
  798.             if (buff[0] == '\0') {
  799.                 redraw = 1;
  800.                 break;
  801.                 }
  802.             if ((in = fopen(buff, "r")) == NULL) {
  803.                 popmsg("Could not load file");
  804.                 getkey();
  805.                 }
  806.             else {
  807.                 OBJECT *obj;
  808.                 set_loadplg_offset(0,0,0);
  809.                 set_loadplg_scale(1,1,1);
  810.                 while ((obj = load_plg(in)) != NULL) {
  811.                     SEGMENT *s;
  812.                     add_to_objlist(objlist, obj);
  813.                     if ((s = new_seg(NULL)) == NULL) {
  814.                         popmsg("Warning -- out of memory!");
  815.                         getkey();
  816.                         }
  817.                     else {
  818.                         seg_setrep(s, obj);
  819.                         update_segment(s);
  820.                         }
  821.                     set_object_owner(obj, s);
  822.                     if (spacestep < object_bounds(obj, &x, &y, &z)/5L)
  823.                         spacestep = object_bounds(obj, &x, &y, &z)/5L;
  824.                     }
  825.                 fclose(in);
  826.                 }
  827.             redraw = 1;
  828.             break;
  829.         case 'S': case 's':
  830.             nextolastkey = 0;
  831.             askfor("File to save? ", buff, 15);
  832.             if (buff[0] == '\0') {
  833.                 redraw = 1;
  834.                 break;
  835.                 }
  836.             if ((out = fopen(buff, "w")) == NULL) {
  837.                 popmsg("Could not open file");
  838.                 getkey();
  839.                 }
  840.             else {
  841.                 OBJECT *obj;
  842.                 for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  843.                     save_plg(obj, out);
  844.                 fclose(out);
  845.                 }
  846.             redraw = 1;
  847.             break;
  848.         case 'Z': case 'z':
  849.             nextolastkey = 0;
  850.             advanced();
  851.             while (bioskey(1)) bioskey(0);  /* flush keyboard buffer */
  852.             redraw = 1; break;
  853.         case 'I': case 'i':
  854.             nextolastkey = 0; disp_info(objlist); redraw = 1; break;
  855.         case 'P': case 'p':
  856.             nextolastkey = 0; disp_palette(); getkey(); redraw = 1; break;
  857.         case 'F': case 'f':
  858.             nextolastkey = 0;
  859.             askfor("Figure file to read? ", buff, 15);
  860.             if (buff[0] == '\0') {
  861.                 redraw = 1;
  862.                 break;
  863.                 }
  864.             if ((in = fopen(buff, "r")) == NULL) {
  865.                 popmsg("Could not load figure file");
  866.                 getkey();
  867.                 }
  868.             else {
  869.                 SEGMENT *s, *readseg();
  870.                 int c;
  871.                 while ((c = getc(in)) != '{')
  872.                     if (c == EOF) {
  873.                         popmsg("Early EOF!");
  874.                         getkey();
  875.                         redraw = 1;
  876.                         break;
  877.                         }
  878.                 set_readseg_objlist(objlist);
  879.                 if ((s = readseg(in, NULL)) == NULL) {
  880.                     popmsg("Error reading figure file");
  881.                     getkey();
  882.                     }
  883.                 else
  884.                     update_segment(s);
  885.                 }
  886.             redraw = 1;
  887.             break;
  888.         case 'H': case 'h': case '?':
  889.             nextolastkey = 0;
  890.             poptext(helptext);
  891.             getkey();
  892.             redraw = 1;
  893.             break;
  894.         case 'O': case 'o':
  895.             nextolastkey = 0;
  896.             set_options();
  897.             redraw = 1;
  898.             break;
  899.         case 'V': case 'v':
  900.             nextolastkey = 0;
  901.             resize_viewport();
  902.             review = redraw = 1;
  903.             break;
  904.         case 'X': case 'x':
  905.             nextolastkey = 0;
  906.             new_features();
  907.             while (bioskey(1)) bioskey(0);  /* flush keyboard buffer */
  908.             review = redraw = 1;
  909.             break;
  910.         case '^': save_pcx_file();
  911.         default: break;
  912.         }
  913.     return 0;
  914. }
  915.  
  916. do_joy(joystick_data *joy)
  917. {
  918.     long dist = spacestep*stepsize;
  919.     float cosvalue, sinvalue;
  920.  
  921.     if (abs(joy->x) < 10 && abs(joy->y) < 10) return 0;
  922.     cosvalue = cosine(current_view->pan);
  923.     sinvalue = sine(current_view->pan);
  924.     switch (joy->buttons)
  925.         {
  926.         case 0:  /* no buttons down */
  927.             current_view->pan += (joy->x * ANGLESTEP*stepsize)/100;
  928.             current_view->ex -= (joy->y * dist * sinvalue)/100;
  929.             current_view->ez -= (joy->y * dist * cosvalue)/100;
  930.             review = redraw = 1;
  931.             break;
  932.         case 1:  /* first button down */
  933.             current_view->ey -= (joy->y * spacestep*stepsize)/100;
  934.             current_view->ex -= (joy->x * dist * cosvalue)/100;
  935.             current_view->ez -= (joy->x * dist * sinvalue)/100;
  936.             review = redraw = 1;
  937.             break;
  938.         case 2:  /* second button down */
  939.             current_view->tilt += (joy->y * ANGLESTEP*stepsize)/100;
  940.             current_view->roll += (joy->x * ANGLESTEP*stepsize)/100;
  941.             review = redraw = 1;
  942.             break;
  943.         case 3:  /* both buttons down */
  944.             current_view->zoom += (joy->y*65536L) / 100;
  945.             review = redraw = 1;
  946.             break;
  947.         default: break;
  948.         }
  949.     return 0;
  950. }
  951.  
  952. static char *adv_menu[] = {
  953.     "Move",
  954.     "Rotate",
  955.     "Twirl",
  956.     "Alter",
  957.     "Paint",
  958.     "Info",
  959.     "Save",
  960.     "Copy",
  961.     "Delete",
  962.     "Unselect",
  963.     "Hack off",
  964.     "Join to",
  965.     "Figure...",
  966.     NULL
  967.     };
  968.  
  969. #include "pointer.h"
  970.  
  971. POINTER pointer;
  972.  
  973. static char *surface_menu[] = { "Normal", "Cosine-lit", "Metal", "Glass", NULL };
  974.  
  975. static char *figure_menu[] = {
  976.     "Figure select",
  977.     "Delete",
  978.     "Save",
  979.     "Copy",
  980.     "Info",
  981.     NULL
  982.     };
  983.  
  984. void select_tree(SEGMENT *s)
  985.     {
  986.     SEGMENT *p; OBJECT *obj;
  987.     if ((obj = seg_getrep(s)) != NULL) highlight_obj(obj);
  988.     for (p = child_segment(s); p; p = sibling_segment(p))
  989.         select_tree(p);
  990.     }
  991.  
  992. void count_tree(SEGMENT *s, int *nsegs, int *nverts, int *npolys)
  993.     {
  994.     SEGMENT *p; OBJECT *obj;
  995.     ++*nsegs;
  996.     if ((obj = seg_getrep(s)) != NULL) {
  997.         int nv, np;
  998.         get_obj_info(obj, &nv, &np, NULL, 0);
  999.         *nverts += nv;  *npolys += np;
  1000.         }
  1001.     for (p = child_segment(s); p; p = sibling_segment(p))
  1002.         count_tree(p, nsegs, nverts, npolys);
  1003.     }
  1004.  
  1005. static void zap_obj(OBJECT *obj)
  1006.     {
  1007.     remove_from_objlist(objlist, obj);
  1008.     delete_obj(obj);
  1009.     }
  1010.  
  1011. static OBJECT *dup_obj(OBJECT *obj, void *owner)
  1012.     {
  1013.     char buff[500];
  1014.     OBJECT *o;
  1015.     int nv, np;
  1016.     get_obj_info(obj, &nv, &np, buff, sizeof(buff));
  1017.     o = copy_obj(obj, nv, np, buff);
  1018.     if (o) {
  1019.         add_to_objlist(objlist, o);
  1020.         set_object_owner(o, owner);
  1021.         unhighlight_obj(o);
  1022.         }
  1023.     return o;
  1024.     }
  1025.  
  1026. advanced()
  1027. {
  1028.     OBJECT *obj;
  1029.     SEGMENT *s, *newparent;
  1030.     void pointer_to_world();
  1031.     int nsegs = 0, nobjs = 0, nverts = 0, npolys = 0, nselected = 0;
  1032.     unsigned surf;
  1033.     char buff[100], *p;
  1034.     FILE *out;
  1035.     char c, d;
  1036.     long oldx, oldy, oldz, oldcx, oldcy, oldcz, dx, dy, dz;
  1037.     unsigned char oldflags;
  1038.     int mx, my;
  1039.     unsigned buttons;
  1040.     time_t now;
  1041.  
  1042.     pointer.port = 0;
  1043.     pointer.gesture = pointer.buttons = 0;
  1044.     pointer.x = pointer.y = pointer.z = 0;
  1045.     pointer.pan = pointer.tilt = pointer.roll = 0;
  1046.     pointer.sx = pointer.sy = pointer.sz = 1;
  1047.     for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1048.         if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1049.             ++nselected;
  1050.     if (nselected == 0)
  1051.         {
  1052.         popmsg("No objects selected!");
  1053.         delay(600);
  1054.         return 0;
  1055.         }
  1056.     poptext(adv_menu);
  1057.     switch (c = toupper(getkey()))
  1058.         {
  1059.         case 'S':
  1060.             refresh_display();
  1061.             if (askfor("Enter filename: ", buff, 20) == 0x1B) break;
  1062.             if (buff[0] == '\0') {
  1063.                 redraw = 1;
  1064.                 break;
  1065.                 }
  1066.             if ((out = fopen(buff, "w")) == NULL)
  1067.                 {
  1068.                 popmsg("Could not create file");
  1069.                 getkey();
  1070.                 break;
  1071.                 }
  1072.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1073.                 {
  1074.                 if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1075.                     {
  1076.                     save_plg(obj, out);
  1077.                     sprintf(buff, "%d object%s saved", ++nobjs,
  1078.                         (nobjs > 1) ? "s" : "");
  1079.                     refresh_display();
  1080.                     popmsg(buff);
  1081.                     }
  1082.                 }
  1083.             refresh_display();
  1084.             sprintf(buff, "Saved %d object%s", nobjs, (nobjs > 1) ? "s" : "");
  1085.             popmsg(buff);
  1086.             getkey();
  1087.             fclose(out);
  1088.             break;
  1089.         case 'I':
  1090.             refresh_display();
  1091.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1092.                 if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1093.                     {
  1094.                     char buff[100];
  1095.                     int nv, np;
  1096.                     ++nobjs;
  1097.                     get_obj_info(obj, &nv, &np, buff, sizeof(buff)-1);
  1098.                     nverts += nv;
  1099.                     npolys += np;
  1100.                     }
  1101.             sprintf(buff, "%d obj%s, %d vertices, %d polygon%s", nobjs, (nobjs > 1) ? "s" : "", nverts, npolys, (npolys > 1) ? "s" : "");
  1102.             popmsg(buff); getkey();
  1103.             break;
  1104.         case 'M':
  1105.             refresh_display();
  1106.             pointer_read(&pointer);
  1107.             oldcx = pointer.x;  oldcy = pointer.y;  oldcz = pointer.z;
  1108.             pointer_to_world(&pointer, current_view, &oldx, &oldy, &oldz);
  1109.             while ((pointer.buttons & 0x01) == 0)
  1110.                 {
  1111.                 long x, y, z;
  1112.                 pointer_to_world(&pointer, current_view, &x, &y, &z);
  1113.                 for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1114.                     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) {
  1115.                         SEGMENT *s;
  1116.                         if ((s = get_object_owner(obj)) != NULL) {
  1117.                             rel_move_segment(s, x - oldx, y - oldy, z - oldz);
  1118.                             update_segment(s);
  1119.                             }
  1120.                         }
  1121.                 refresh_display();
  1122.                 oldx = x; oldy = y; oldz = z;
  1123.                 pointer_read(&pointer);
  1124.                 }
  1125.             while (pointer.buttons & 0x01) pointer_read(&pointer);
  1126.             refresh_display();
  1127.             break;
  1128.         case 'R':
  1129.         case 'T':
  1130.             refresh_display();
  1131.             pointer_read(&pointer);
  1132.             oldcx = oldx = pointer.x;
  1133.             oldcy = oldy = pointer.y;
  1134.             oldcz = oldz = pointer.z;
  1135.             while ((pointer.buttons & 0x01) == 0)
  1136.                 {
  1137.                 long x, y, z;
  1138.                 if (c == 'R')
  1139.                     {
  1140.                     x = 32768L*(pointer.y - oldy);
  1141.                     y = 32768L*(pointer.x - oldx);
  1142.                     z = 32768L*(pointer.z - oldz);
  1143.                     }
  1144.                 else
  1145.                     {
  1146.                     x = 3276L*(pointer.y - oldcy);
  1147.                     y = 3276L*(pointer.x - oldcx);
  1148.                     z = 3276L*(pointer.z - oldcz);
  1149.                     }
  1150.                 for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1151.                     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) {
  1152.                         SEGMENT *s;
  1153.                         if ((s = get_object_owner(obj)) != NULL) {
  1154.                             rel_rot_segment(s, x, y, z);
  1155.                             update_segment(s);
  1156.                             }
  1157.                         }
  1158.                 refresh_display();
  1159.                 oldx = pointer.x; oldy = pointer.y; oldz = pointer.z;
  1160.                 pointer_read(&pointer);
  1161.                 }
  1162.             while (pointer.buttons & 0x01) pointer_read(&pointer);
  1163.             refresh_display();
  1164.             break;
  1165.         case 'A':
  1166.             refresh_display();
  1167.             poptext(surface_menu);
  1168.             switch (toupper(getkey())) {
  1169.                 case 'N': surf = 0x0000; break;
  1170.                 case 'C': surf = 0x1000; break;
  1171.                 case 'M': surf = 0x2000; break;
  1172.                 case 'G': surf = 0x3000; break;
  1173.                 default: return 0;
  1174.                 }
  1175.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1176.                 {
  1177.                 int nv, np, i;
  1178.                 if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) {
  1179.                     get_obj_info(obj, &nv, &np, NULL, 0);
  1180.                     for (i = 0; i < np; ++i) {
  1181.                         unsigned color;
  1182.                         get_poly_info(obj, i, &color, &nv, NULL, 0);
  1183.                         set_poly_color(obj, i, (color & 0xCFFF) | surf);
  1184.                         }
  1185.                     }
  1186.                 }
  1187.             refresh_display();
  1188.             break;
  1189.         case 'P':
  1190.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1191.                 {
  1192.                 int nv, np, i;
  1193.                 if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) {
  1194.                     get_obj_info(obj, &nv, &np, NULL, 0);
  1195.                     for (i = 0; i < np; ++i)
  1196.                         set_poly_color(obj, i, 0x8000 | paint);
  1197.                     }
  1198.                 }
  1199.             refresh_display();
  1200.             break;
  1201.         case 'D':
  1202.             refresh_display();
  1203.             sprintf(buff, "Delete %d object%s!  Are you sure?", nselected, (nselected > 1) ? "s" : "");
  1204.             popmsg(buff);
  1205.             if (toupper(getkey()) != 'Y') break;
  1206.             refresh_display();
  1207.             obj = first_in_objlist(objlist);
  1208.             while (obj) {
  1209.                 OBJECT *nextobj;
  1210.                 nextobj = next_in_objlist(objlist, obj);
  1211.                 if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED)) {
  1212.                     if ((s = get_object_owner(obj)) != NULL)
  1213.                         seg_setrep(s, NULL);
  1214.                     remove_from_objlist(objlist, obj);
  1215.                     delete_obj(obj);
  1216.                     refresh_display();
  1217.                     }
  1218.                 if (bioskey(1)) {
  1219.                     popmsg("Aborted");
  1220.                     break;
  1221.                     }
  1222.                 obj = nextobj;
  1223.                 }
  1224.             break;
  1225.         case 'U':
  1226.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1227.                 {
  1228.                 set_obj_flags(obj, get_obj_flags(obj) & ~OBJ_HIGHLIGHTED);
  1229.                 unhighlight_obj(obj);
  1230.                 }
  1231.             break;
  1232.         case 'C':
  1233.             refresh_display();
  1234.             askfor("X,Y,Z offset: ", buff, 20);
  1235.             if (buff[0] == '\0') break;
  1236.             refresh_display();
  1237.             sscanf(buff, "%ld,%ld,%ld", &dx, &dy, &dz);
  1238.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1239.                 if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) && (s = get_object_owner(obj)) != NULL) {
  1240.                     SEGMENT *n;
  1241.                     n = copy_segment(s, dx, dy, dz, dup_obj);
  1242.                     if (n) update_segment(n);
  1243.                     }
  1244.             break;
  1245.         case 'H':
  1246.             refresh_display();
  1247.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1248.                 if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) && (s = get_object_owner(obj)) != NULL) {
  1249.                     detach_segment(s);
  1250.                     update_segment(s);
  1251.                     }
  1252.             break;
  1253.         case 'J':
  1254.             refresh_display();
  1255.             popmsg("Click on new parent");
  1256.             while (!mouse_read(&mx, &my, &buttons));
  1257.             refresh_display();
  1258.             newparent = NULL;
  1259.             do {
  1260.                 OBJECT *newobj;
  1261.                 do { mouse_read(&mx, &my, &buttons); } while (buttons == 0);
  1262.                 do { mouse_read(&mx, &my, &buttons); } while (buttons);
  1263.                 newobj = where_screen_pt(NULL, NULL, mx, my);
  1264.                 if (newobj)
  1265.                     if ((get_obj_flags(newobj) & OBJ_HIGHLIGHTED) == 0)
  1266.                         newparent = get_object_owner(newobj);
  1267.                 } while (newparent == NULL);
  1268.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1269.                 if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) && (s = get_object_owner(obj)) != NULL) {
  1270.                     attach_segment(s, newparent);
  1271.                     update_segment(s);
  1272.                     }
  1273.             break;
  1274.         case 'F':
  1275.             refresh_display();
  1276.             poptext(figure_menu);
  1277.             for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1278.                 if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) && (s = get_object_owner(obj)) != NULL)
  1279.                     break;
  1280.             if (obj == NULL || s == NULL) {
  1281.                 popmsg("No objects selected!");
  1282.                 getkey();
  1283.                 return 0;
  1284.                 }
  1285.             switch (toupper(getkey())) {
  1286.                 case 'F':
  1287.                     select_tree(find_root_segment(s));  /* and down again */
  1288.                     break;
  1289.                 case 'D':
  1290.                     refresh_display();
  1291.                     popmsg("Delete entire figure! Are you sure?");
  1292.                     if (toupper(getkey()) != 'Y') break;
  1293.                     refresh_display();
  1294.                     delete_segment(find_root_segment(s), zap_obj);
  1295.                     break;
  1296.                 case 'C':
  1297.                     refresh_display();
  1298.                     askfor("X,Y,Z offset: ", buff, 20);
  1299.                     if (buff[0] == '\0') break;
  1300.                     refresh_display();
  1301.                     sscanf(buff, "%ld,%ld,%ld", &dx, &dy, &dz);
  1302.                     s = copy_segment(find_root_segment(s), dx, dy, dz, dup_obj);
  1303.                     if (s) update_segment(s);
  1304.                     break;
  1305.                 case 'I':
  1306.                     count_tree(find_root_segment(s), &nsegs, &nverts, &npolys);
  1307.                     sprintf(buff, "%d segs, %d verts, %d polys", nsegs, nverts, npolys);
  1308.                     popmsg(buff);
  1309.                     getkey();
  1310.                     break;
  1311.                 case 'S':
  1312.                     refresh_display();
  1313.                     askfor("Filename: ", buff, 20);
  1314.                     if (buff[0] == '\0') break;
  1315.                     refresh_display();
  1316.                     if ((out = fopen(buff, "w")) == NULL) {
  1317.                         popmsg("Could not create file");
  1318.                         getkey();
  1319.                         break;
  1320.                         }
  1321.                     askfor("Comment: ", buff, 20);
  1322.                     if ((p = strchr(buff, ';')) != NULL) *p = '\0';
  1323.                     fprintf(out, "Comment = %s;\n", buff);
  1324.                     time(&now);
  1325.                     strcpy(buff, ctime(&now));
  1326.                     if ((p = strchr(buff, '\n')) != NULL) *p = '\0';
  1327.                     fprintf(out, "Comment = Saved from %s %s;\n", progname, buff);
  1328.                     writeseg(out, find_root_segment(s), 0);
  1329.                     fclose(out);
  1330.                     break;
  1331.                 default: return 0;
  1332.                 }
  1333.             break;
  1334.         default: break;
  1335.         }
  1336.     return 0;
  1337. }
  1338.  
  1339.  
  1340. do_mouse(int x, int y, unsigned buttons)
  1341. {
  1342.     if (buttons & 0x01)
  1343.         {
  1344.         OBJECT *obj;
  1345.         int pol, vert;
  1346.  
  1347.         obj = where_screen_pt(&pol, NULL, x, y);
  1348.         if (obj)
  1349.             {
  1350.             unsigned color;
  1351.             int n;
  1352.             get_poly_info(obj, pol, &color, &n, NULL, 0);
  1353.             set_poly_color(obj, pol, color ^ 0x8000);
  1354.             set_obj_flags(obj, get_obj_flags(obj) ^ OBJ_HIGHLIGHTED);
  1355.             if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1356.                 highlight_obj(obj);
  1357.             else
  1358.                 unhighlight_obj(obj);
  1359.             redraw = 1;
  1360. }
  1361.         else
  1362.             {
  1363.             popmsg("Not on any object");
  1364.             delay(300);
  1365.             }
  1366.         redraw = 1;
  1367.         while (buttons & 0x01) mouse_read(&x, &y, &buttons);
  1368.         }
  1369.     return 0;
  1370. }
  1371.  
  1372.  
  1373. /* find world coordinates of pointer based on given view */
  1374.  
  1375. void pointer_to_world(POINTER *p, VIEW *v, long *x, long *y, long *z)
  1376. {
  1377.     MATRIX m,n;
  1378.     *x = p->x;
  1379.     *y = p->y;
  1380.     *z = p->z;
  1381.     make_matrix(m,v->tilt, v->pan, v->roll, v->ex, v->ey, v->ez);
  1382.     inverse_matrix(m, n);
  1383.     matrix_point(n,x,y,z);
  1384. }
  1385.  
  1386. static char *optmenu[] = {
  1387.     "Background",
  1388.     "Reflection",
  1389.     "Logo",
  1390.     NULL };
  1391.  
  1392. set_options()
  1393.     {
  1394.     poptext(optmenu);
  1395.     switch (toupper(getkey())) {
  1396.         case 'B': fancy_background = !fancy_background; break;
  1397.         case 'R': reflection_pool = !reflection_pool;
  1398.                             if(reflection_pool)    current_view->bottom = 160;
  1399.                             else current_view->bottom = 199;
  1400.                             break;
  1401.         case 'L': show_logo = !show_logo; break;
  1402.         default: break;
  1403.         }
  1404.     return 0;
  1405.     }
  1406.  
  1407. load_logo(char *filename)
  1408.     {
  1409.     char far *buffer;
  1410.     FILE *in;
  1411.     if ((in = fopen(filename, "rb")) == NULL) return 0;
  1412.     if (load_pcx(in, 3)) {  /* some sort of problem loading it in */
  1413.         fclose(in);
  1414.         return 0;
  1415.         }
  1416.     fclose(in);
  1417.     return 1;  /* all is well... we have a logo */
  1418.     }
  1419.  
  1420. resize_viewport()
  1421.     {
  1422.     int top, left, bottom, right;
  1423.     unsigned buttons;
  1424.     popmsg("Click top-left and drag");
  1425.     do { mouse_read(&left, &top, &buttons); } while (buttons == 0);
  1426.     while (buttons) {
  1427.         while (!mouse_read(&right, &bottom, &buttons));
  1428.         refresh_display();
  1429.         vgabox(left, top, right, bottom, 15);
  1430.         }
  1431.     current_view->left = left;  current_view->right = right;
  1432.     current_view->top = top;   current_view->bottom = bottom;
  1433.     refresh_display();
  1434.     return 0;
  1435.     }
  1436.  
  1437. save_pcx_file()
  1438.     {
  1439.     char filename[100];
  1440.     char far *buffer;
  1441.     FILE *out;
  1442.     refresh_display();
  1443.     askfor("File to save to? ", filename, 20);
  1444.     if (filename[0] == '\0') return 1;
  1445.     refresh_display();
  1446.     if ((out = fopen(filename, "wb")) == NULL) {
  1447.         popmsg("Could not open file");
  1448.         getkey();
  1449.         return 3;
  1450.         }
  1451.     mouse_hide();
  1452.     save_pcx(out, v_page);
  1453.     mouse_show(v_page);
  1454.     fclose(out);
  1455.     return 0;
  1456.     }
  1457.  
  1458. /* Some support routines */
  1459.  
  1460. static void center(char *s, int w)
  1461. {
  1462.     int n;
  1463.  
  1464.     if (strlen(s) == 0) return;
  1465.     n = (w - strlen(s)) / 2;
  1466.     memmove(&s[n], s, strlen(s)+1);
  1467.     memset(s, ' ', n);
  1468. }
  1469.  
  1470. disp_status(VIEW *v)
  1471. {
  1472.     char *text[9], a[80], b[80], c[80], d[80], e[80], f[80], g[80];
  1473.     int w, i;
  1474.  
  1475.     text[0] = a; text[1] = "";
  1476.     text[2] = b; text[3] = c; text[4] = d; text[5] = e; text[6] = f;
  1477.     text[7] = g; text[8] = NULL;
  1478.     sprintf(a, "STATUS");
  1479.  
  1480.     sprintf(b, "X = %ld  Y = %ld  Z = %ld", v->ex, v->ey, v->ez);
  1481.     w = strlen(b);
  1482.     sprintf(c, "Pan = %ld   Tilt = %ld   Roll = %ld  ", v->pan/65536L, v->tilt/65536L, v->roll/65536L);
  1483.     if (strlen(c) > w) w = strlen(c);
  1484.     sprintf(d, "Zoom = %ld", v->zoom/65536L);
  1485.     if (strlen(d) > w) w = strlen(d);
  1486.     sprintf(e, "Hither = %ld  Yon = %ld", v->hither, v->yon);
  1487.     if (strlen(e) > w) w = strlen(e);
  1488.  
  1489.     if (have_joystick)
  1490.         {
  1491.         joystick_read(&joy);
  1492.         sprintf(f, "Joystick = %d,%d", joy.x, joy.y);
  1493.         if (strlen(f) > w) w = strlen(f);
  1494.         }
  1495.     else
  1496.         text[6] = NULL;
  1497.     text[7] = NULL;
  1498.  
  1499.     for (i = 0; text[i]; ++i) center(text[i], w);
  1500.     poptext(text);
  1501.     return 0;
  1502. }
  1503.  
  1504. static char *joyprompt1[] = {
  1505.         "    JOYSTICK CALIBRATION",
  1506.         "",
  1507.         "  Please move the joystick",
  1508.         " forward and left, and then",
  1509.         " hit either joystick button",
  1510.         NULL
  1511.         };
  1512.  
  1513. static char *joyprompt2[] = {
  1514.         "         Thank you!",
  1515.         "",
  1516.         "  Now please move the joystick",
  1517.         "joystick back and right and then",
  1518.         "   hit either joystick button",
  1519.         NULL
  1520.         };
  1521.  
  1522.  
  1523. void joystick_calibration(joystick_data *joy)
  1524. {
  1525.     if (have_joystick == 0) return;
  1526.     if (have_joystick & 1) joystick_init(joy, 0);
  1527.     else if (have_joystick & 2) joystick_init(joy, 1);
  1528.  
  1529.     joystick_setscale(joy, 100);
  1530.     poptext(joyprompt1);
  1531.     joystick_scale(joy, 0);
  1532.     poptext(joyprompt2);
  1533.     joystick_scale(joy, 1);
  1534. }
  1535.  
  1536. disp_info(OBJLIST *objlist)
  1537. {
  1538.     OBJECT *obj;
  1539.     int nobjs = 0, nverts = 0, npolys = 0;
  1540.     char buff[100];
  1541.  
  1542.     for (obj = first_in_objlist(objlist); obj; obj = next_in_objlist(objlist, obj))
  1543.         {
  1544.         int nv, np;
  1545.  
  1546.         get_obj_info(obj, &nv, &np, buff, sizeof(buff)-1);
  1547.         ++nobjs; nverts += nv; npolys += np;
  1548.         }
  1549.     sprintf(buff, "%d object%s, %d vertices, %d polygon%s", nobjs,
  1550.         (nobjs > 1) ? "s" : "", nverts, npolys, (npolys > 1) ? "s" : "");
  1551.     popmsg(buff);
  1552.     getkey();
  1553.     return 0;
  1554. }
  1555.  
  1556. collided(SEGMENT *hitter, SEGMENT *hit, long x, long y, long z)
  1557.     {
  1558.     putchar(7);
  1559.     return 1;
  1560.     }
  1561.  
  1562. #ifdef HAVEBOUNDS
  1563. extern MATRIX *get_seg_matrix();
  1564.  
  1565. check_coll(SEGMENT *seg, OBJLIST *olist)
  1566.     {
  1567.     long x, y, z;
  1568.     OBJECT *obj;
  1569.     SEGMENT *s;
  1570.     void *p;
  1571.     for (p = first_hotspot(seg, &x, &y, &z); p; p = next_hotspot(p, &x, &y, &z)) {
  1572.         matrix_point(get_seg_matrix(seg), &x, &y, &z);  /* convert point to world coordinates */
  1573.         for (obj = first_in_objlist(olist); obj; obj = next_in_objlist(olist, obj))
  1574.             if ((s = get_object_owner(obj)) != NULL)
  1575.                 if (pt_in_segment(s, x, y, z))
  1576.                     return collided(seg, s, x, y, z);
  1577.         }
  1578.     return 0;
  1579.     }
  1580. #endif
  1581.  
  1582. static char *featmenu[] = {
  1583.     "Select Surface type",
  1584.     "Choose Color",
  1585.     "Paint Polys",
  1586.     NULL
  1587.     };
  1588.  
  1589. static char *surfmenu[] = {
  1590.     "Absolute",
  1591.     "Cosine-lit",
  1592.     "Metal",
  1593.     "Glass",
  1594.     NULL
  1595.     };
  1596.  
  1597. void disp_palette()
  1598.     {
  1599.     int i, j, page;
  1600.     page = mouse_hide();
  1601.     for (i = 0; i < 16; i++)
  1602.         for (j = 0; j < 16; j++)
  1603.             user_box(j*10,i*8,j*10+9,i*8+8,i*16+j);
  1604.     mouse_show(page);
  1605.     }
  1606.  
  1607. static unsigned stype[] = { 0, 0x1000, 0x2000, 0x3000 };
  1608.  
  1609. unsigned paint = 1;
  1610. static unsigned surface = 0x1000;
  1611. static unsigned paintcolor = 1;
  1612.  
  1613. new_features()
  1614.     {
  1615.     int x, y, c, i;
  1616.     unsigned buttons;
  1617.     char buff[100];
  1618.     if (!have_mouse)
  1619.         {
  1620.         popmsg("No mouse");
  1621.         getkey();
  1622.         return 3;
  1623.         }
  1624. #ifdef MOUSING
  1625.     c = menu(featmenu);
  1626.     c = ("SCP")[c];
  1627. #else
  1628.     poptext(featmenu);
  1629.     c = toupper(getkey());
  1630. #endif
  1631.     switch (c)
  1632.         {
  1633.         case 'S':        /* select surface */
  1634. #ifdef MOUSING
  1635.             i = menu(surfmenu);
  1636.             surface = stype[i];
  1637. #else
  1638.             poptext(surfmenu);
  1639.             switch (toupper(getkey())) {
  1640.                 case 'N': surface = stype[0]; break;
  1641.                 case 'C': surface = stype[1]; break;
  1642.                 case 'M': surface = stype[2]; break;
  1643.                 case 'G': surface = stype[3]; break;
  1644.                 }
  1645.             if (surface == 0)
  1646.                 paint = paintcolor;
  1647.             else
  1648.                 paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10);        /* hue, brightness *16 */
  1649. #endif
  1650.             refresh_display();
  1651.             break;
  1652.  
  1653.         case 'C': /* select color */
  1654.             disp_palette();
  1655.             while (mouse_read(&x, &y, &buttons) == 0);
  1656.             disp_palette();
  1657.             do {
  1658.                 do { mouse_read(&x, &y, &buttons); } while (!buttons);
  1659.                 do { mouse_read(&x, &y, &buttons); } while (buttons);
  1660.                 } while (y > 191);
  1661.             paintcolor = 16*(y/8) + x/10;
  1662.             if (surface == 0)
  1663.                 paint = paintcolor;
  1664.             else
  1665.                 paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10);        /* hue, brightness *16 */
  1666.             refresh_display();
  1667.             break;
  1668.  
  1669.         case 'P':
  1670.             refresh_display();
  1671.             do {
  1672.                 if (kbhit()) break;
  1673.                 while (mouse_read(&x, &y, &buttons) == 0 && !kbhit());
  1674.                 if (buttons & 0x01) {
  1675.                     OBJECT *obj;
  1676.                     int poly;
  1677.                     obj = where_screen_pt(&poly, NULL, x, y);
  1678.                     if (obj) {
  1679.                         set_poly_color(obj, poly, paint);
  1680.                         refresh_display();
  1681.                         }
  1682.                     }
  1683.                 } while (!(buttons & 0x02));
  1684.             break;
  1685.         default: break;
  1686.         }
  1687.     return 0;
  1688.     }
  1689.  
  1690.